package fr.irit.etracetool.eobjectgraph;

import java.util.HashSet;
import java.util.Hashtable;
import java.util.Set;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.zest.core.widgets.Graph;
import org.eclipse.zest.core.widgets.GraphConnection;
import org.eclipse.zest.core.widgets.GraphNode;
import org.eclipse.zest.layouts.LayoutStyles;
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;

public class BipartiteGraph {
	
	private Set<Node> sources;
	private Set<Node> targets;
	
	public BipartiteGraph() {
		sources = new HashSet<Node>();
		targets = new HashSet<Node>();
	}

	public Set<Node> getSources() {
		return sources;
	}

	public Set<Node> getTargets() {
		return targets;
	}

	public static boolean contains(Set<Node> set, EObject e) {
		for (Node n : set) {
			if (EcoreUtil.equals(n.getElement(), e)) {
				return true;
			}
		}
		return false;
	}

	protected void addInSources(EObject e) {
		if (!BipartiteGraph.contains(sources, e)){
			sources.add(new Node(e));
		}
	}
	protected void addInTargets(EObject e) {
		if (!BipartiteGraph.contains(targets, e)){
			targets.add(new Node(e));
		}
	}

	public Node getInSources(EObject e) {
		for (Node n : sources) {
			if (EcoreUtil.equals(e, n.getElement())) {
				return n;
			}
		}
		return null;
	}

	public Node getInTargets(EObject e) {
		for (Node n : targets) {
			if (EcoreUtil.equals(e, n.getElement())) {
				return n;
			}
		}
		return null;
	}

	public void add(EObject source, EObject target) {
		addInSources(source);
		addInTargets(target);
		getInSources(source).addSucc(getInTargets(target));
		getInTargets(target).addSucc(getInSources(source));
	}
	
	public String toString() {
		StringBuffer sb = new StringBuffer();
		for (Node n : sources) {
			if (n.getElement() instanceof NamedElement) 
				sb.append(((NamedElement) n.getElement()).getName() + " " + "("+ ((NamedElement) n.getElement()).getClass().getSimpleName() + "): \n");
			else sb.append(n.getElement().toString() + " : \n");
			for (Node succ : n.getSuccessor()) {
				if (succ.getElement() instanceof NamedElement) 
					sb.append("\t" + ((NamedElement) succ.getElement()).getName() + " " + "("+ ((NamedElement) succ.getElement()).getClass().getSimpleName() + ") \n");
				else sb.append("\t" +  succ.getElement() + " : \n");
			}
		}
		return sb.toString();
	}
	
	public void createAndDisplayShell() {
		Display d = new Display();
		Shell shell = new Shell(d);
		shell.setText("Traces");
		shell.setLayout(new FillLayout());
		shell.setSize(1240, 780);

		Graph g = new Graph(shell, SWT.NONE);
		Hashtable<Node, GraphNode> hashTable= new Hashtable<Node, GraphNode>();
		for (Node n : sources) {
			GraphNode gn;
			if (n.getElement() instanceof NamedElement) {
				gn = new GraphNode(g, SWT.NONE, ((NamedElement) n.getElement()).getName());
				gn.setForegroundColor(new org.eclipse.swt.graphics.Color(null, 255, 128, 0));
			} else gn = new GraphNode(g, SWT.NONE, n.getElement().toString());
			hashTable.put(n, gn);
		}
		for (Node n : targets) {
			GraphNode gn; 
			if (n.getElement() instanceof NamedElement) {
				gn = new GraphNode(g, SWT.NONE, ((NamedElement) n.getElement()).getName());
			} else gn = new GraphNode(g, SWT.NONE, n.getElement().toString());
			hashTable.put(n, gn);
		}
		for (Node n : sources) {
			for (Node suc : n.getSuccessor()) {
				new GraphConnection(g, SWT.NONE, hashTable.get(n), hashTable.get(suc));
			}
		}
		g.setLayoutAlgorithm(new SpringLayoutAlgorithm(LayoutStyles.ENFORCE_BOUNDS), true);
		//NO_LAYOUT_NODE_RESIZING
		//ENFORCE_BOUNDS
		shell.open();
		while (!shell.isDisposed()) {
			while (!d.readAndDispatch()) {
				d.sleep();
			}
		}
	}
}
	


